package com.wcs.exam.common.config;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.wcs.exam.common.base.Result;
import com.wcs.exam.common.base.exception.BaseException;
import com.wcs.exam.common.cache.CacheCount;
import com.wcs.exam.common.constant.BaseConstant;
import com.wcs.exam.common.constant.RedisConstant;
import com.wcs.exam.common.util.JsonUtil;
import com.wcs.exam.common.util.JwtUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.io.IOException;
import java.util.List;

/**
 * @author wcs
 */
@Slf4j
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowCredentials(true).allowedOriginPatterns("*").allowedMethods("*").allowedHeaders("*").exposedHeaders("*");
    }

    /**
     * 拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthInterceptorConfig()).addPathPatterns("/v1/auth/**");
        registry.addInterceptor(new AdminInterceptorConfig()).addPathPatterns("/v1/admin/**").excludePathPatterns("/v1/admin/login/**");
    }

    public static class AuthInterceptorConfig implements AsyncHandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
            String token = request.getHeader(BaseConstant.TOKEN);
            if (ObjectUtil.isEmpty(token)) {
                response(response, "web token is missing");
                return false;
            }
            DecodedJWT jwt = JwtUtil.verify(token);
            ThreadContext.setUserId(JwtUtil.getUserId(jwt));

            // 统计在线人数
            CacheCount cacheCount = SpringUtil.getBean(CacheCount.class);
            cacheCount.setOnlineUser(ThreadContext.getUserId());
            return true;
        }

        @Override
        public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex) {
            ThreadContext.removeUserId();
        }
    }

    public static class AdminInterceptorConfig implements AsyncHandlerInterceptor {
        /**
         * admin不需要权限校验的接口
         */
        private static final List<String> EXCLUDE_URL = List.of(
                "/v1/admin/sys/user/current"
        );

        @Override
        public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
            String token = request.getHeader(BaseConstant.TOKEN);
            if (ObjectUtil.isEmpty(token)) {
                response(response, "admin token is missing");
                return false;
            }
            DecodedJWT jwt = JwtUtil.verify(token);
            ThreadContext.setUserId(JwtUtil.getUserId(jwt));

            if (!checkUri(request.getRequestURI())) {
                throw new BaseException(306, "没此权限，请联系管理员");
            }
            return true;
        }

        @Override
        public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex) {
            ThreadContext.removeUserId();
        }

        // 校验用户是否有权限
        private static Boolean checkUri(String uri) {
            StringRedisTemplate stringRedisTemplate = SpringUtil.getBean(StringRedisTemplate.class);
            String tk = stringRedisTemplate.opsForValue().get(RedisConstant.System.ADMIN_APIS.concat(ThreadContext.getUserId().toString()));

            if (StringUtils.hasText(uri) && uri.endsWith("/")) {
                uri = uri.substring(0, uri.length() - 1);
            }
            // 额外不需要权限校验的接口
            if (EXCLUDE_URL.contains(uri)) {
                return true;
            }
            // 权限校验
            if (StringUtils.hasText(tk) && tk.contains(uri)) {
                return true;
            }
            log.error("用户缺少权限点：{}", uri);
            return false;
        }
    }

    private static void response(HttpServletResponse response, String message) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().append(JsonUtil.toJsonString(Result.error(message)));
    }

}
